package com.kexio.core.security.filter;

import com.kexio.core.security.service.UserContextService;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 用户上下文初始化过滤器
 * 负责在请求开始时初始化基础上下文信息，在请求结束时清理
 *
 * @author Kexio Team
 * @since 1.0.0
 */
public class UserContextInitFilter implements Filter {

    private static final Logger log = LoggerFactory.getLogger(UserContextInitFilter.class);
    
    private static final String REQUEST_ID_HEADER = "X-Request-ID";
    private static final String REQUEST_ID_ATTRIBUTE = "requestId";
    private static final String START_TIME_ATTRIBUTE = "startTime";

    private final UserContextService userContextService;

    public UserContextInitFilter(UserContextService userContextService) {
        this.userContextService = userContextService;
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("==> Kexio UserContext Init Filter 初始化完成");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        // 记录请求开始时间
        long startTime = System.currentTimeMillis();
        httpRequest.setAttribute(START_TIME_ATTRIBUTE, startTime);

        // 生成或获取请求ID
        String requestId = getOrGenerateRequestId(httpRequest);
        httpRequest.setAttribute(REQUEST_ID_ATTRIBUTE, requestId);
        httpResponse.setHeader(REQUEST_ID_HEADER, requestId);

        // 设置基础请求信息
        setRequestInfo(httpRequest);

        // 记录请求基础信息
        logRequestStart(httpRequest, requestId);

        try {
            // 继续处理请求
            chain.doFilter(request, response);
            
        } catch (Exception e) {
            log.error("处理请求时发生异常, requestId={}", requestId, e);
            throw e;
            
        } finally {
            // 清理用户上下文
            userContextService.clearUserContext();
            
            // 记录请求完成信息
            logRequestEnd(httpRequest, httpResponse, requestId, startTime);
            
            // 清理请求相关的ThreadLocal变量
            cleanupRequestContext();
        }
    }

    @Override
    public void destroy() {
        log.info("==> Kexio UserContext Init Filter 销毁完成");
    }

    /**
     * 获取或生成请求ID
     *
     * @param request HttpServletRequest
     * @return 请求ID
     */
    private String getOrGenerateRequestId(HttpServletRequest request) {
        String requestId = request.getHeader(REQUEST_ID_HEADER);
        if (requestId == null || requestId.trim().isEmpty()) {
            requestId = generateRequestId();
        }
        return requestId;
    }

    /**
     * 生成请求ID
     *
     * @return 请求ID
     */
    private String generateRequestId() {
        return UUID.randomUUID().toString().replace("-", "").substring(0, 16);
    }

    /**
     * 设置请求信息
     *
     * @param request HttpServletRequest
     */
    private void setRequestInfo(HttpServletRequest request) {
        // 获取客户端IP
        String clientIp = getClientIpAddress(request);
        request.setAttribute("clientIp", clientIp);

        // 获取User-Agent
        String userAgent = request.getHeader("User-Agent");
        request.setAttribute("userAgent", userAgent);

        // 获取来源页面
        String referer = request.getHeader("Referer");
        request.setAttribute("referer", referer);

        // 设置请求方法和URI
        request.setAttribute("method", request.getMethod());
        request.setAttribute("requestURI", request.getRequestURI());
        request.setAttribute("queryString", request.getQueryString());

        // 如果是AJAX请求，标记一下
        String xRequestedWith = request.getHeader("X-Requested-With");
        boolean isAjax = "XMLHttpRequest".equals(xRequestedWith);
        request.setAttribute("isAjax", isAjax);
    }

    /**
     * 获取客户端真实IP地址
     *
     * @param request HttpServletRequest
     * @return 客户端IP地址
     */
    private String getClientIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }

        // 如果通过多级代理，IP地址可能包含多个，取第一个
        if (ip != null && ip.contains(",")) {
            ip = ip.split(",")[0].trim();
        }

        return ip;
    }

    /**
     * 记录请求开始日志
     *
     * @param request   HttpServletRequest
     * @param requestId 请求ID
     */
    private void logRequestStart(HttpServletRequest request, String requestId) {
        if (!log.isDebugEnabled()) {
            return;
        }

        String method = request.getMethod();
        String requestURI = request.getRequestURI();
        String queryString = request.getQueryString();
        String clientIp = (String) request.getAttribute("clientIp");

        StringBuilder logMessage = new StringBuilder();
        logMessage.append("请求开始 [").append(requestId).append("] ");
        logMessage.append(method).append(" ").append(requestURI);
        
        if (queryString != null && !queryString.isEmpty()) {
            logMessage.append("?").append(queryString);
        }
        
        logMessage.append(" from ").append(clientIp);

        log.debug(logMessage.toString());
    }

    /**
     * 记录请求结束日志
     *
     * @param request   HttpServletRequest
     * @param response  HttpServletResponse
     * @param requestId 请求ID
     * @param startTime 开始时间
     */
    private void logRequestEnd(HttpServletRequest request, HttpServletResponse response, 
                              String requestId, long startTime) {
        if (!log.isDebugEnabled()) {
            return;
        }

        long endTime = System.currentTimeMillis();
        long duration = endTime - startTime;
        
        String method = request.getMethod();
        String requestURI = request.getRequestURI();
        int status = response.getStatus();

        log.debug("请求完成 [{}] {} {} - {} ({}ms)", 
                requestId, method, requestURI, status, duration);

        // 记录慢请求
        if (duration > 3000) { // 超过3秒的请求
            log.warn("慢请求警告 [{}] {} {} - {}ms", 
                    requestId, method, requestURI, duration);
        }
    }

    /**
     * 清理请求上下文
     */
    private void cleanupRequestContext() {
        // 这里可以清理一些自定义的ThreadLocal变量
        // 目前主要由UserContextService负责清理用户上下文
    }
}
